package org.lemon.cla.controller;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.lemon.cla.enums.HttpStatusEnum;
import org.lemon.cla.dto.response.ResponseResult;
import org.lemon.cla.dto.request.UserSearchRequest;
import org.lemon.cla.dto.response.UserResponse;
import org.lemon.cla.enums.UserRoleEnum;
import org.lemon.cla.pojo.User;
import org.lemon.cla.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.Optional; // 导入Optional

import org.lemon.cla.exception.BusinessException; // 导入自定义业务异常


@RestController
@RequestMapping("/users")
@Tag(name = "用户管理", description = "提供用户信息的CRUD操作及相关查询")
public class UserController {

    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private IUserService userService;


    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Schema(description = "修改密码请求对象")
    public static class ChangePasswordRequest {
        @NotBlank(message = "旧密码不能为空")
        @Schema(description = "旧密码", required = true, example = "old_password")
        private String oldPassword;

        @NotBlank(message = "新密码不能为空")
        @Schema(description = "新密码", required = true, example = "new_password")
        private String newPassword;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Schema(description = "修改头像请求对象")
    public static class ChangeAvatarRequest {
        @NotBlank(message = "头像URL不能为空")
        @Schema(description = "新头像URL", required = true, example = "http://example.com/new_avatar.jpg")
        private String newAvatarUrl;
    }
    // --- End DTOs ---


    @Operation(summary = "创建新用户(慎用⚠️)", description = "根据提供的用户数据创建一个新用户。该接口仅用于管理员直接添加用户，注册功能请使用Auth模块的注册接口。使用不当可能破坏数据一致性。",
            responses = {
                    @ApiResponse(responseCode = "201", description = "用户创建成功"),
                    @ApiResponse(responseCode = "400", description = "请求参数错误或用户名已存在"),
                    @ApiResponse(responseCode = "500", description = "服务器内部错误")
            })
    @PostMapping
    @PreAuthorize("hasRole('管理员')")
    public ResponseResult<User> createUser(
            @io.swagger.v3.oas.annotations.parameters.RequestBody( // 使用 OpenAPI 的 RequestBody 注解
                    description = "用户对象，包含用户名、密码和角色",
                    required = true,
                    content = @Content(schema = @Schema(implementation = User.class))
            ) @org.springframework.web.bind.annotation.RequestBody @Valid User user) { // Spring MVC 的 @RequestBody 注解

        // 校验用户名是否已存在，如果存在则抛出业务异常
        Optional.ofNullable(userService.getUserByUsername(user.getUsername()))
                .ifPresent(existingUser -> {
                    throw new BusinessException(HttpStatusEnum.CONFLICT.getCode(), "用户创建失败：用户名已存在。");
                });

        user.setPassword(passwordEncoder.encode(user.getPassword())); // 🚨 密码加密
        user.setCreateTime(LocalDateTime.now()); // 默认创建时间
        user.setLastLogin(LocalDateTime.now()); // 初始登录时间
        // 使用 Optional 处理默认值，防止空指针，同时避免 if-else
        user.setAvatarUrl(Optional.ofNullable(user.getAvatarUrl())
                .filter(url -> !url.isEmpty())
                .orElse("https://2025-1333181667.cos.ap-shanghai.myqcloud.com/2025shixun/default_avatar.ico"));
        user.setRole(Optional.ofNullable(user.getRole()).orElse(UserRoleEnum.STUDENT)); // 确保角色有值
        user.setIsDeleted(Optional.ofNullable(user.getIsDeleted()).orElse(false)); // 默认未逻辑删除

        boolean saved = userService.save(user); // 如果save返回false但没抛异常，表示操作未成功
        if (!saved) {
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "用户创建失败，请检查输入或联系管理员。");
        }
        user.setPassword(null); // 返回前清空密码
        return ResponseResult.success(HttpStatusEnum.CREATED.getCode(), "用户创建成功", user);
    }

    @Operation(summary = "根据ID获取用户", description = "通过用户ID查询并返回单个用户的信息 (不含密码)")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取用户"),
            @ApiResponse(responseCode = "404", description = "用户未找到")
    })
    @GetMapping("/{id}")
    public ResponseResult<User> getUserById(
            @Parameter(description = "用户唯一ID", required = true, example = "1") @PathVariable("id") Integer id) {
        // 使用Optional简化null检查，如果未找到则抛出 NotFoundException
        return Optional.ofNullable(userService.getById(id))
                .map(user -> {
                    user.setPassword(null); // 明确移除密码
                    return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), "用户获取成功", user);
                })
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "用户未找到。")); // 抛出 NotFoundException
    }

    @Operation(summary = "更新用户信息", description = "根据用户ID更新现有用户的信息，**只传入需要更新的字段**。此接口由管理员操作。")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "用户更新成功"),
            @ApiResponse(responseCode = "400", description = "请求参数错误或没有需要更新的字段"),
            @ApiResponse(responseCode = "404", description = "用户未找到")
    })
    @PutMapping("/{id}")
    @PreAuthorize("hasRole('管理员')")
    public ResponseResult<User> updateUser(
            @Parameter(description = "用户唯一ID", required = true, example = "1") @PathVariable("id") Integer id,
            @io.swagger.v3.oas.annotations.parameters.RequestBody(
                    description = "用户更新对象，只传入需要更新的字段（如username, realName等，密码请使用单独接口）",
                    required = true,
                    content = @Content(schema = @Schema(implementation = User.class))
            ) @org.springframework.web.bind.annotation.RequestBody User user) {

        User existingUser = Optional.ofNullable(userService.getById(id))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "更新失败：指定用户不存在或已逻辑删除。")); // 抛出 NotFoundException

        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("user_id", id);

        Optional.ofNullable(user.getUsername()).ifPresent(val -> updateWrapper.set("username", val));
        Optional.ofNullable(user.getAvatarUrl()).ifPresent(val -> updateWrapper.set("avatar_url", val));

        if (user.getPassword() != null && !user.getPassword().isEmpty()) {
            throw new BusinessException(HttpStatusEnum.NOT_MODIFIED.getCode(), "请使用'/users/change-password'接口修改密码。"); // 抛出 BadRequestException
        }
        Optional.ofNullable(user.getRole()).ifPresent(val -> updateWrapper.set("role", val));
        Optional.ofNullable(user.getRealName()).ifPresent(val -> updateWrapper.set("real_name", val));
        Optional.ofNullable(user.getPhone()).ifPresent(val -> updateWrapper.set("phone", val));
        Optional.ofNullable(user.getEmail()).ifPresent(val -> updateWrapper.set("email", val));

        // 检查是否有实际的 SET 操作
        if (updateWrapper.getSqlSet() != null && !updateWrapper.getSqlSet().isEmpty()) {
            boolean updated = userService.update(null, updateWrapper);
            if (!updated) {
                throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "用户更新失败，请稍后重试。"); // 抛出 ServiceException
            }
            // 刷新并返回最新状态
            User updatedUser = Optional.ofNullable(userService.getById(id))
                    .orElseThrow(() -> new BusinessException(HttpStatusEnum.SUCCESS.getCode(), "用户更新成功，但无法重新获取用户数据。")); // 抛出 ServiceException
            updatedUser.setPassword(null);
            return ResponseResult.success("用户更新成功", updatedUser);
        } else {
            // 没有字段需要更新
            User currentUpdatedUser = Optional.ofNullable(userService.getById(id))
                    .orElseThrow(() -> new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "无法获取用户数据。")); // 抛出 ServiceException
            currentUpdatedUser.setPassword(null);
            return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), "没有需要更新的字段。", currentUpdatedUser);
        }
    }

    @Operation(summary = "用户自己修改密码", description = "用户通过提供旧密码来修改自己的登录密码。")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "密码修改成功"),
            @ApiResponse(responseCode = "400", description = "请求参数错误、旧密码不正确或新密码不符合要求"),
            @ApiResponse(responseCode = "401", description = "未认证"),
            @ApiResponse(responseCode = "404", description = "用户未找到")
    })
    @PutMapping("/change-password")
    @PreAuthorize("isAuthenticated()")
    public ResponseResult<Void> changePassword(
            @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "旧密码和新密码", required = true, content = @Content(schema = @Schema(implementation = ChangePasswordRequest.class)))
            @org.springframework.web.bind.annotation.RequestBody @Valid ChangePasswordRequest request,
            @AuthenticationPrincipal User currentUser) {

        Long currentUserId = Optional.ofNullable(currentUser)
                .map(User::getUserId)
                .map(Long::valueOf)
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "无法获取当前登录用户ID。")); // 抛出 ServiceException

        User userInDb = Optional.ofNullable(userService.getById(currentUserId.intValue()))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "当前用户不存在或已逻辑删除。")); // 抛出 NotFoundException

        if (!passwordEncoder.matches(request.getOldPassword(), userInDb.getPassword())) {
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "旧密码不正确。"); // 抛出 BadRequestException
        }

        userInDb.setPassword(passwordEncoder.encode(request.getNewPassword()));
        boolean updated = userService.updateById(userInDb);

        if (!updated) {
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "密码修改失败，请稍后重试。"); // 抛出 ServiceException
        }
        return ResponseResult.success("密码修改成功！");
    }


    @Operation(summary = "用户自己修改头像", description = "用户修改自己的头像URL。")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "头像修改成功"),
            @ApiResponse(responseCode = "400", description = "请求参数错误"),
            @ApiResponse(responseCode = "401", description = "未认证"),
            @ApiResponse(responseCode = "404", description = "用户未找到")
    })
    @PutMapping("/change-avatar")
    @PreAuthorize("isAuthenticated()")
    public ResponseResult<Void> changeAvatar(
            @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "新头像URL", required = true, content = @Content(schema = @Schema(implementation = ChangeAvatarRequest.class)))
            @org.springframework.web.bind.annotation.RequestBody @Valid ChangeAvatarRequest request,
            @AuthenticationPrincipal User currentUser) {

        Long currentUserId = Optional.ofNullable(currentUser)
                .map(User::getUserId)
                .map(Long::valueOf)
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "无法获取当前登录用户ID。")); // 抛出 ServiceException

        User userInDb = Optional.ofNullable(userService.getById(currentUserId.intValue()))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "当前用户不存在或已逻辑删除。")); // 抛出 NotFoundException

        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("user_id", currentUser.getUserId())
                .set("avatar_url", request.getNewAvatarUrl());

        boolean updated = userService.update(null, updateWrapper);

        if (!updated) {
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "头像修改失败，请稍后重试。"); // 抛出 ServiceException
        }
        return ResponseResult.success("头像修改成功！");
    }


    @Operation(summary = "物理删除用户(慎用⚠️⚠️⚠️)", description = "使用之前务必备份数据库⚠️⚠️⚠️根据用户ID删除指定用户",
            parameters = @Parameter(name = "id", description = "用户唯一ID", required = true, example = "1"),
            responses = {
                    @ApiResponse(responseCode = "204", description = "用户删除成功"),
                    @ApiResponse(responseCode = "404", description = "用户未找到"),
                    @ApiResponse(responseCode = "500", description = "服务器内部错误")
            })
    @DeleteMapping("/{id}/deleteHard")
    @PreAuthorize("hasRole('管理员')")
    public ResponseResult<Void> deleteUser(
            @Parameter(description = "用户ID", required = true, example = "1") @PathVariable("id") Integer id) {
        // 校验用户是否存在
        Optional.ofNullable(userService.getById(id))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "删除失败：指定用户不存在或已逻辑删除。")); // 抛出 NotFoundException

        boolean removed = userService.removeById(id); // 🚨 再次强调：这里在有 @TableLogic 时执行的是逻辑删除
        if (!removed) {
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "用户删除失败，请稍后重试。"); // 抛出 ServiceException
        }
        return ResponseResult.success(HttpStatusEnum.NO_CONTENT.getCode(), "用户删除成功", null);
    }

    @Operation(summary = "分页获取所有用户", description = "获取用户列表，支持分页查询，返回用户不含密码信息。")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取用户列表",
                    content = @Content(mediaType = "application/json",
                            schema = @Schema(implementation = ResponseResult.class,
                                    subTypes = IPage.class)))
    })
    @GetMapping
    public ResponseResult<IPage<UserResponse>> getAllUsers(
            @Parameter(description = "页码", example = "1") @RequestParam(defaultValue = "1") Integer pageNum,
            @Parameter(description = "每页记录数", example = "10") @RequestParam(defaultValue = "10") Integer pageSize) {

        Page<UserResponse> page = new Page<>(pageNum, pageSize);
        IPage<UserResponse> userPage = userService.searchUsersByConditions(page, new UserSearchRequest());

        return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), "成功获取用户列表", userPage);
    }

    @Operation(summary = "根据用户名获取用户", description = "通过用户名查询并返回单个用户的信息 (不含密码)")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取用户",
                    content = @Content(mediaType = "application/json",
                            schema = @Schema(implementation = ResponseResult.class,
                                    subTypes = User.class))),
            @ApiResponse(responseCode = "404", description = "用户未找到")
    })
    @GetMapping("/username/{username}")
    public ResponseResult<User> getUserByUsername(
            @PathVariable("username") String username) {
        return Optional.ofNullable(userService.getUserByUsername(username))
                .map(user -> {
                    user.setPassword(null);
                    return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), "成功获取用户信息", user);
                })
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "用户未找到。")); // 抛出 NotFoundException
    }

    @Operation(summary = "模糊查询用户(查询首选)", description = "根据用户名、角色、真名、手机号、邮箱、创建时间等进行模糊查询，返回不含密码的用户信息列表")
    @PostMapping("/search")
    public ResponseResult<IPage<UserResponse>> searchUsers(
            @Parameter(description = "页码", example = "1") @RequestParam(defaultValue = "1") Integer pageNum,
            @Parameter(description = "每页数量", example = "10") @RequestParam(defaultValue = "10") Integer pageSize,
            @io.swagger.v3.oas.annotations.parameters.RequestBody(
                    description = "用户查询请求对象 (可选，用于筛选)", required = false, content = @Content(schema = @Schema(implementation = UserSearchRequest.class)))
            @org.springframework.web.bind.annotation.RequestBody @Valid UserSearchRequest request) {

        Page<UserResponse> page = new Page<>(pageNum, pageSize);

        request = Optional.ofNullable(request).orElseGet(UserSearchRequest::new);

        IPage<UserResponse> resultPage = userService.searchUsersByConditions(page, request);

        return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), resultPage);
    }

    @Operation(summary = "逻辑删除用户(推荐)", description = "根据用户ID将用户标记为已删除状态，数据不从数据库中移除。关联的数据字段会变为未知或null⚠️",
            parameters = @Parameter(name = "id", description = "用户唯一ID", required = true, example = "1"),
            responses = {
                    @ApiResponse(responseCode = "200", description = "用户逻辑删除成功"),
                    @ApiResponse(responseCode = "404", description = "用户未找到"),
                    @ApiResponse(responseCode = "500", description = "逻辑删除失败")
            })
    @DeleteMapping("/{id}/softDelete")
    @PreAuthorize("hasRole('管理员')")
    public ResponseResult<Void> deleteUserSoft(
            @Parameter(description = "用户ID", required = true, example = "1") @PathVariable("id") Integer id) {
        Optional.ofNullable(userService.getById(id))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "逻辑删除失败：用户不存在或已处于删除状态。"));

        boolean removed = userService.setLogicalDeleteStatus(id, true);

        if (!removed) {
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "用户逻辑删除失败，请稍后重试。");
        }
        return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), "用户已逻辑删除", null);
    }


    @Operation(summary = "恢复逻辑删除用户", description = "根据用户ID将用户从逻辑删除状态恢复为正常状态。")
    @Parameters({
            @Parameter(name = "id", description = "用户唯一ID", required = true, example = "1")
    })
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "用户恢复成功"),
            @ApiResponse(responseCode = "404", description = "用户未找到"),
            @ApiResponse(responseCode = "500", description = "用户恢复失败")
    })
    @PutMapping("/{id}/recover")
    @PreAuthorize("hasRole('管理员')")
    public ResponseResult<Void> recoverUser(
            @PathVariable("id") Integer id) {
        boolean updated = userService.setLogicalDeleteStatus(id, false); // 尝试恢复

        if (!updated) {

            User user = userService.getById(id); // 这个 getById 受 @TableLogic 影响，只查未逻辑删除的


            if (user == null) { // 用户确实不存在或者被逻辑删除
                throw new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "用户恢复失败：用户不存在或无法被恢复。"); // 抛出 NotFoundException
            } else { // 用户存在且未被逻辑删除，却尝试恢复（setLogicalDeleteStatus会返回false）
                throw new BusinessException(HttpStatusEnum.CONFLICT.getCode(), "用户已是正常状态，无需恢复。"); // 抛出 BadRequestException
            }
        }
        return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), "用户恢复成功", null);
    }
}
